// CoreCalc, a spreadsheet core implementation
// ----------------------------------------------------------------------
// Copyright (c) 2006-2009 Peter Sestoft and others

// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

//  * The above copyright notice and this permission notice shall be
//    included in all copies or substantial portions of the Software.

//  * The software is provided "as is", without warranty of any kind,
//    express or implied, including but not limited to the warranties of
//    merchantability, fitness for a particular purpose and
//    noninfringement.  In no event shall the authors or copyright
//    holders be liable for any claim, damages or other liability,
//    whether in an action of contract, tort or otherwise, arising from,
//    out of or in connection with the software or the use or other
//    dealings in the software.
// ----------------------------------------------------------------------

using System;
using System.Text;
using System.Reflection;

namespace CoreCalc
{
  /// <summary>
  /// An absolute cell address, including reference to a sheet.
  /// </summary>
  public class FullCellAddr : IEquatable<FullCellAddr>
  {
    public readonly CellAddr ca;
    public readonly Sheet sheet;    // non-null
    public static readonly MethodInfo evalMethod =
      typeof(FullCellAddr).GetMethod("Eval");

    public FullCellAddr(CellAddr ca, Sheet sheet)
    {
      this.ca = ca;
      this.sheet = sheet;
    }

    public FullCellAddr(int col, int row, Sheet sheet)
      : this(new CellAddr(col, row), sheet) { }

    public FullCellAddr(string A1Format, Sheet sheet)
      : this(new CellAddr(A1Format), sheet) { }

    public bool Equals(FullCellAddr other)
    {
      return ca.Equals(other.ca) && sheet == other.sheet;
    }

    public override int GetHashCode()
    {
      return ca.GetHashCode() * 29 + sheet.GetHashCode();
    }

    public override bool Equals(Object o)
    {
      return o is FullCellAddr && Equals((FullCellAddr)o);
    }

    public override string ToString()
    {
      StringBuilder sb = new StringBuilder();
      sb.Append(sheet.ToString() + "!").Append(ca);
      return sb.ToString();
    }

    public Value Eval()
    {
      Cell cell = sheet[ca];
      if (cell != null)
        return cell.Eval(sheet, ca.col, ca.row);
      else // TODO: inconsistent with other blank cell eval.
        return ErrorValue.Make("Null value");
    }

    public bool TryGetCell(out Cell currentCell)
    {
      currentCell = sheet[ca];
      return (currentCell != null);
    }
  }
}